﻿using System;
using System.Collections.Generic;
using System.Linq;

using LostLib.Linq;

using NTypeClasses;
using System.Diagnostics;
using TypeClassSample.Math;
using TypeClassSample.Monad;

namespace TypeClassSample
{
	class TypeClassSampleProgram
	{
		static void Main()
		{
			var a = new Vector3D<double>(1, 0, 0);
			var b = new Vector3D<double>(0, 1, 0);
			Console.WriteLine("({0}) + ({1}) = ({2})", a, b, a + b);
			Debug.Assert(a + b == new Vector3D<double> (1, 1, 0));
			Debug.Assert(Vector3D<double>.Zero + a == a);
			//if (Debugger.IsAttached)
			//    Console.ReadKey();

			var my5 = Option.Just(5);
			Func<int, Option<int>> mulBy2 = x => Option.Just(x * 2);

			var list = new[] {2, 1, 0, -1};
			Filter<Option<bool>, Option<IEnumerable<int>>, int>(v => Option.Just(v > 0), list)
			.Iter(filtered => filtered.ForEach(Console.Write, () => Console.Write(", ")));
			Console.WriteLine();

			if (Debugger.IsAttached)
				Console.ReadKey();
		}

		static GenTList Filter<GenBool, GenTList, T>(Func<T, GenBool> filter, IEnumerable<T> elems){
			var listMonad = TypeClass<Monad<GenTList, GenTList, IEnumerable<T>, IEnumerable<T>>>.Instance;
			var boolMonad = TypeClass<Monad<GenBool, GenTList, bool, IEnumerable<T>>>.Instance;
			if (!elems.Any()) return listMonad.Return(new T[] {});
			
			var head = elems.First();
			return boolMonad.Bind(filter(head), allowed => {
				var tail = elems.Skip(1);
				var filteredTail = Filter<GenBool, GenTList, T>(filter, tail);
				return listMonad.Bind(filteredTail, (IEnumerable<T> ys) =>
					                                listMonad.Return(allowed ? new[] {head}.Concat(ys) : ys));
			});
		}
	}
}
